package cn.flying.cloud.task.core.handler;

import javax.annotation.Resource;

import java.time.Duration;
import java.time.LocalDateTime;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import cn.flying.cloud.base.common.utils.Ft;
import cn.flying.cloud.task.core.model.JobContext;
import cn.flying.cloud.task.core.quartz.enums.JobExecuteStatusEnum;
import cn.flying.cloud.task.core.quartz.exception.TaskException;
import cn.flying.cloud.task.entity.TaskJobLog;
import cn.flying.cloud.task.service.TaskJobLogService;

/**
 * @author: admin
 * @date: 2025年03月12日 23:54
 * @version: 1.0
 */
public abstract class AbstractJobHandler {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    // 注入Spring事务管理器
    @Resource
    private PlatformTransactionManager transactionManager;
    @Resource
    private TaskJobLogService taskJobLogService;

    /**
     * 执行的抽象方法
     */
    public void executeJob(JobContext context) {
        // 1. 初始化事务定义（新建事务）
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        definition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(definition);

        TaskJobLog log = new TaskJobLog();
        log.setSerialNo(context.getSerialNo());
        log.setServiceName(context.getServiceName());
        log.setJobDate(context.getJobDate());
        log.setJobName(context.getJobName());
        log.setJobType(context.getJobType());
        log.setJobGroup(context.getJobGroup());
        log.setJobDesc(context.getJobDesc());
        log.setJobParam(Ft.JSON.serializer(context.getJobParam()));
        log.setJobHost(context.getHost());
        log.setJobStatus(JobExecuteStatusEnum.RUNNING.getCode());
        log.setStartTime(LocalDateTime.now());
        log.setTenantId(context.getTenantId());

        try {
            log.setFireTime(LocalDateTime.now());
            execute(context);
            // 执行成功
            log.setJobStatus(JobExecuteStatusEnum.SUCCESS.getCode());
            log.setJobMsg(JobExecuteStatusEnum.SUCCESS.getDesc());

            // 2. 业务执行成功，提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            logger.error("任务执行失败！", e);
            // 执行失败
            log.setJobStatus(JobExecuteStatusEnum.FAIL.getCode());
            log.setJobMsg(e.getMessage());
            log.setJobTrace(ExceptionUtils.getStackTrace(e));

            // 3. 发生异常，回滚事务
            transactionManager.rollback(status);
        } finally {
            log.setEndTime(LocalDateTime.now());
            log.setDuration(Duration.between(log.getFireTime(), log.getEndTime()).toMillis());

            // 执行失败告警通知
            if (JobExecuteStatusEnum.FAIL.getCode().equals(log.getJobStatus())) {
                // TODO
            }

            // 日志保存建议使用新事务，避免被业务事务影响
            saveJobLogWithNewTransaction(log);
        }
    }

    /**
     * 单独的事务保存日志，确保日志一定会被记录
     */
    private void saveJobLogWithNewTransaction(TaskJobLog log) {
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        definition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(definition);

        try {
            taskJobLogService.createObj(log);
            transactionManager.commit(status);
        } catch (Exception e) {
            logger.error("日志保存失败", e);
            transactionManager.rollback(status);
        }
    }

    /**
     * 执行
     */
    public abstract void execute(JobContext jobContext) throws TaskException;


}
